package mytree

import (
	"strconv"
	"strings"

	"gitee.com/hailib/mytree/errs"
)

// Layer 层级
type Layer string

const LayerNil Layer = ""

func NewLayer(id Id) Layer {
	return Layer(id.String() + "/")
}

// String 获取字符串
func (l Layer) String() string {
	return string(l)
}

func (l Layer) NotNil() bool {
	return l != LayerNil
}

func (l Layer) IsNil() bool {
	return l == LayerNil
}

func (l Layer) Join(child Id) Layer {
	return l + Layer(child.String()) + "/"
}

// isChildOf 判断当前层级是否是目标层级的后代
func (l Layer) IsChildOf(target Layer) bool {
	return target.NotNil() && l != target && strings.HasPrefix(string(l), string(target))
}

// Parents 获取所有上级 Id
func (l Layer) Parents() ([]Id, Error) {
	if l.IsNil() {
		return nil, errs.New(errs.InvalidParam, 210903145307, "layer is nil")
	}

	ids := make([]Id, 0)
	parent := l.Parent()

	for {
		if parent.IsNil() {
			return ids, nil
		}
		id, err := parent.Id()
		if err != nil {
			return make([]Id, 0), err
		}
		ids = append(ids, id)
		parent = parent.Parent()
	}
}

// idStart 查找自身 id 开始的位置
// 1. '1/'.idStart()   -> 0
// 2. '1/2/'.idStart() -> 2
func (l Layer) idStart() int {
	if l.IsNil() {
		return 0
	}

	for i := len(l) - 2; i >= 0; i-- {
		if l[i] == '/' {
			return i + 1
		}
	}
	return 0
}

func (l Layer) Verify() Error {
	if l.IsNil() {
		return nil
	}
	size := len(l)
	if l[size-1] != '/' {
		return errs.New(errs.InvalidParam, 210903163731, "invalid layer: %s", l)
	}
	return nil
}

// Parent 获取父级
func (l Layer) Parent() Layer {
	if l.IsNil() {
		return l
	}

	for i := len(l) - 2; i >= 0; i-- {
		s := l[i]
		if s == '/' {
			return l[0 : i+1]
		}
	}
	return LayerNil
}

// Id 获取层级的 Id
// 1.如果层级为空，则返回 IdNil 并没有任何错误
// 2.如果层级不以 '/' 以尾则报错
// 3.如果 最后一串 xx/ 中的 xx 不为 uint32 字符串则返回错误
func (l Layer) Id() (Id, Error) {
	if l.IsNil() {
		return IdNil, nil
	}
	err := l.Verify()
	if err != nil {
		return IdNil, err
	}

	idstr := l[l.idStart() : len(l)-1]
	num, serr := strconv.ParseInt(idstr.String(), 10, 64)
	if serr != nil {
		return IdNil, errs.New(errs.InvalidParam, 210903161435, "parse id err, layer: %s", l)
	}

	return IdFromI64(num)
}
